# 在文件顶部添加Django环境初始化
import json
import os
from datetime import datetime
from django.conf import settings
import django

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'FSJY.settings.settings')
django.setup()
from channels.generic.websocket import AsyncWebsocketConsumer
from django.core.cache import cache
from channels.db import database_sync_to_async
from user.models import UserProfile
from socket_chat import models
# F() 表达式用于直接引用数据库字段的值，
# 允许在数据库层面进行操作而不是在Python内存中处理
from django.db.models import CharField, F
from django.db.models.functions import Cast
from django.contrib.auth.models import AnonymousUser
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from channels.layers import get_channel_layer
"""
    AsyncWebsocketConsumer中一定要使用异步方法，否则会报错
"""
# 在文件顶部新增导入
import redis



class chatConsumer(AsyncWebsocketConsumer):
    """WebSocket消费者，用于实时推送用户余额变更"""

    async def connect(self):
        """处理WebSocket连接请求"""
        #   从url路径参数中获取用户ID,我在中间件中判断是否登录，
        #   登陆后把user对象放到了scope中
        user = self.scope['user']
        print("user是%s" % user)
        if not user.is_authenticated:
            print('未登录')
            await self.close(code=4001)  # 自定义关闭代码
            return
        print('已登录')
        self.user_id = user.id  # 使用认证用户的ID
        # 创建用户专属频道组名
        self.room_name = f'private_{self.user_id}'
        # 将当前用户加入到频道组中
        # 唯一性：每个# WebSocket# 连接会自动生成唯一的channel_name（格式类似"!hijklmn1234rV2"）
        await self.channel_layer.group_add(
            self.room_name,
            self.channel_name
        )
        # 接受WebSocket连接
        await self.accept()
        not_received_message = await self.get_undelivered_messages()
        not_received_notification_message = await self.get_not_received_notify(self.user_id)
        if not_received_notification_message:
            print("当前用户未接收的通知消息", not_received_notification_message)
            # 把消息标记为已接收
            # 使用await来确保异步操作完成后再继续执行，异步操作并未成功，所以改为同步
            await self.mark_notification_messages_received()
            await self.send_batch_messages(not_received_notification_message,"notify")
            print("把通知标记为已接收")
        print('当前用户未接收的消息', not_received_message)
        if not_received_message:
            await self.send_batch_messages(not_received_message,"text")
            # 把消息标记为已接收
            self.mark_messages_received()

    async def disconnect(self, close_code):
        """处理WebSocket断开连接请求"""
        # 确保 room_name 已初始化
        if hasattr(self, 'room_name'):
            print('断开链接')
            await self.channel_layer.group_discard(
                self.room_name,
                self.channel_name
            )
            print("成功移除用户频道组", self.room_name)
        else:
            print("room_name 未初始化")

    async def receive(self, text_data):
        try:
            try:
                data = json.loads(text_data)
            except json.JSONDecodeError as e:
                print(f"JSON解码错误: {str(e)}")
                return
            print("data拿到了")
            receiver_id = data['receiver']
            print(f"receiver_id: {receiver_id}")
            receiver = await self.get_user_obj(receiver_id)
            print(receiver)
            if not receiver:
                print('接收者不存在')
                return
            content = data['content']
            content_type = str(data['type'])
            # 将前端类型转换为合法的处理方法名
            handler_type = f"{content_type}_message".replace(" ", "_").lower()
            # 大坑。django的cache.get获取不到redis中的channels组，改为这种原生方式无问题
            try:
                r = redis.Redis(host='localhost', port=6379, db=0)
                #
                group_key = f"asgi:group:private_{receiver_id.id}"
                # 获取有序集合成员数量
                member_count = r.zcard(group_key)
                is_received = member_count > 0
                print(f'用户在线状态: {is_received}（成员数：{member_count}）')
            except Exception as e:
                print("未发送消息")
                print(f'Redis查询失败: {str(e)}')
                is_received = False
            time_now=str(datetime.now())
            # 转发给接收者
            # channel_layer.group_send的作用是将消息发送到频道组，
            # 而不是直接发送给客户端。每个连接到WebSocket的消费者都有一个频道名，
            # 加入同一个组的消费者可以接收到发送到该组的消息。但发送到组后，需要对应的处理方法（handler）来处理这些消息，
            # 然后通过self.send发送给客户端，也就是说这里是具体的处理逻辑，
            await self.channel_layer.group_send(
                f"private_{receiver_id}",
                {
                    # 这个type表示要调用的方法名，
                    "type":handler_type,
                    "message":{
                        "type": content_type,
                        "sender": self.scope['user'].id,
                        "content": content,
                        "timestamp": time_now,
                        "is_received": is_received,
                        "is_read": False,
                        }
                    }
            )
            print("转发未报错")
            print(self.scope['user'])
            # 保存消息到数据库
            await self.__save_message(self.scope['user'], receiver, content, content_type, is_received,time_now)
        except Exception as e:
            print(f"Error handling message: {str(e)}")

    async def notify_message(self, event):
        """处理通知消息"""
        await self.send(text_data=json.dumps({
            'type': 'notify',
            'content': event['message']['content'],
            'friend': event['message']['friend'],
            'timestamp': str(event['message']['timestamp']),
            'is_read': event['message']['is_read'],
        }))
    @database_sync_to_async
    def __save_message(self, sender, receiver, content, content_type, is_received,time_now):
        models.PrivateMessage.objects.create(
            sender=sender,
            receiver=receiver,
            content=content,
            type=content_type,
            is_received=is_received,
            timestamp=time_now,
        )

    # 新增点：为不同类型创建专用处理方法
    async def text_message(self, event):
        """处理文本类型消息"""
        await self.send(text_data=json.dumps({
            'type': 'text',
            'sender': event['message']['sender'],
            'content': event['message']['content'],
            'timestamp': event['message']['timestamp'],
            'is_received': event['message']['is_received'],
            'is_read': event['message']['is_read'],
        }))

    async def image_message(self, event):
        """处理图片类型消息"""
        await self.send(text_data=json.dumps({
            'type': 'image',
            'sender': event['message']['sender'],
            'content': event['message']['content'],
            'timestamp': event['message']['timestamp']
        }))
    # 新增批量获取消息方法
    @database_sync_to_async
    def get_undelivered_messages(self):
        return list(models.PrivateMessage.objects.filter(
            receiver=self.user_id,
            is_received=False
        ).annotate(
            str_timestamp=Cast('timestamp', output_field=CharField(max_length=50))
        ).values(
        "sender",
        "receiver",
        "content",
        "type",
        "timestamp",
        "is_read",
        "is_received"
        # 使用转换后的字符串时间戳
        ))
    # 发送通知消息直接把配对成功的好友信息一并发送
    @database_sync_to_async
    def get_not_received_notify(self, receiver_id):
        from user.serializers import UserProfileSerializer
        not_received_notify_queryset=models.notificationMessage.objects.filter(receiver=self.user_id,is_received=False)
        notify_list=[]
        if not not_received_notify_queryset:
            return False
        for notify in not_received_notify_queryset:
            print(notify.timestamp)
            notify_list.append({
                'content': notify.content,
                'friend': UserProfileSerializer(notify.friend).data,
                'timestamp': str(notify.timestamp),
                'is_received': notify.is_received,
                'is_read': notify.is_read,
            })
        return notify_list
    # 批量发送方法
    async def send_batch_messages(self, messages,message_type):
        if messages:
            # self.send用于向已建立的 WebSocket 连接发送文本数据
            await self.send(text_data=json.dumps({
                'send_type': 'many',
                'messages': messages,
                'type': message_type,
            }))
            # 批量标记为已接收
            await self.mark_messages_received()

    # 批量标记为已接收
    @database_sync_to_async
    def mark_messages_received(self):
        models.PrivateMessage.objects.filter(
            receiver=self.user_id,
            is_received=False
        ).update(is_received=True)
    #把通知批量标记为已接收
    @database_sync_to_async
    def mark_notification_messages_received(self):
        print('标记已接收')
        models.notificationMessage.objects.filter(
            receiver=self.user_id,
            is_received=False
        ).update(is_received=True)
    @database_sync_to_async
    def get_user_obj(self, user_id):
        return UserProfile.objects.get(id=user_id)
